package com.huffman.smart_picture.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huffman.smart_picture.common.auth.AuthConstant;
import com.huffman.smart_picture.common.UserSession;
import com.huffman.smart_picture.common.exception.BusinessException;
import com.huffman.smart_picture.common.exception.ErrorEnum;
import com.huffman.smart_picture.domain.constants.CommonConstant;
import com.huffman.smart_picture.domain.entity.User;
import com.huffman.smart_picture.domain.entity.UserVipExchange;
import com.huffman.smart_picture.domain.entity.VipExchangeCode;
import com.huffman.smart_picture.domain.enums.UserVipEnum;
import com.huffman.smart_picture.domain.enums.VipDurationTimeEnum;
import com.huffman.smart_picture.domain.request.exchange.VipExchangeCreateRequest;
import com.huffman.smart_picture.mapper.SequenceVipMapper;
import com.huffman.smart_picture.service.UserService;
import com.huffman.smart_picture.service.UserVipExchangeService;
import com.huffman.smart_picture.service.VipExchangeCodeService;
import com.huffman.smart_picture.mapper.VipExchangeCodeMapper;
import com.huffman.smart_picture.utils.ThrowUtil;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author Administrator
 * @description 针对表【vip_exchange_code(会员兑换)】的数据库操作Service实现
 * @createDate 2025-06-08 20:29:24
 */
@Service
@AllArgsConstructor
public class VipExchangeCodeServiceImpl extends ServiceImpl<VipExchangeCodeMapper, VipExchangeCode>
        implements VipExchangeCodeService {

    private final TransactionTemplate transactionTemplate;

    private final UserService userService;

    private final UserVipExchangeService userVipExchangeService;

    private final SequenceVipMapper sequenceVipMapper;

    private static final String LOCK_PRE = "exchangeVip:";


    @Override
    public boolean createVipExchangeCode(VipExchangeCreateRequest vipExchangeCreateRequest, UserSession userSession) {
        String code = vipExchangeCreateRequest.getCode();
        Integer type = vipExchangeCreateRequest.getType();
        Integer duration = vipExchangeCreateRequest.getDuration();
        Date expireTime = vipExchangeCreateRequest.getExpireTime();
        Integer totalCount = vipExchangeCreateRequest.getTotalCount();
        ThrowUtil.throwIf(VipDurationTimeEnum.getEnumByValue(type) == null, ErrorEnum.PARAM_ILLICIT, "有效期类型不存在");
        ThrowUtil.throwIf(duration == null, ErrorEnum.PARAM_ILLICIT, "有效期不存在");
        ThrowUtil.throwIf(expireTime == null, ErrorEnum.PARAM_ILLICIT, "兑换码过期时间未设置");
        if (StrUtil.isBlank(code)) {
            code = UUID.randomUUID().toString(true);
        }
        String lock = LOCK_PRE + code;
        boolean res;
        // 单机锁
        synchronized (lock.intern()) {
            boolean exists = getBaseMapper().exists(new LambdaQueryWrapper<VipExchangeCode>().eq(VipExchangeCode::getCode, code));
            ThrowUtil.throwIf(exists, ErrorEnum.PARAM_ILLICIT, "当前兑换码已存在");
            VipExchangeCode vipExchangeCode = new VipExchangeCode();
            vipExchangeCode.setCode(code);
            vipExchangeCode.setType(type);
            vipExchangeCode.setDuration(duration);
            vipExchangeCode.setExpireTime(expireTime);
            vipExchangeCode.setSurplusCount(totalCount);
            vipExchangeCode.setTotalCount(totalCount);
            res = save(vipExchangeCode);
        }

        return res;
    }

    @Override
    public boolean exchangeVip(String code, HttpServletRequest httpServletRequest) {
        LambdaQueryWrapper<VipExchangeCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VipExchangeCode::getCode, code);
        VipExchangeCode exchangeCode = getOne(queryWrapper);
        ThrowUtil.throwIf(exchangeCode == null, ErrorEnum.RESOURCE_NOT_FIND, "兑换码不存在");
        // 判断兑换码是否过期
        Date now = new Date();
        ThrowUtil.throwIf(exchangeCode.getExpireTime().before(now), ErrorEnum.CHECK_INFO_EXPIRED, "兑换码已过期");
        // 保持原子性
        AtomicReference<UserSession> userSession = new AtomicReference<>((UserSession) httpServletRequest.getSession().getAttribute(AuthConstant.LOGIN_USER));
        Long userId = userSession.get().getId();
        // 单机锁 锁用户id+兑换码
        String lock = userId.toString() + ":" + code;
        boolean res;
        synchronized (lock.intern()) {
            // 判断当前用户是否兑换过当前兑换码
            boolean exists = userVipExchangeService.lambdaQuery()
                    .eq(UserVipExchange::getUserId, userId)
                    .eq(UserVipExchange::getCode, code)
                    .exists();
            ThrowUtil.throwIf(exists, ErrorEnum.REQUEST_MANY, "当前兑换码用户已使用");

            res = Boolean.TRUE.equals(transactionTemplate.execute(status -> {
                User user = userService.getById(userId);
                ThrowUtil.throwIf(user == null, ErrorEnum.CHECK_INFO_EXPIRED, "用户不存在");
                // 默认未找到枚举情况下 持续时间为一天
                Long time = Optional.ofNullable(VipDurationTimeEnum.getEnumByValue(exchangeCode.getType()))
                        .map(VipDurationTimeEnum::getTimeUnit)
                        .orElse(CommonConstant.ONE_DAY);
                // 过期时间 = 当前时间+兑换码持续时间*基本时间单位
                long addExpireTime = exchangeCode.getDuration() * time;
                // 设置过期时间 用户vip未过期直接加 用户vip过期 当前时间上加
                Date userVipExpireTime = user.getVipExpireTime();
                if (userVipExpireTime != null && userVipExpireTime.after(now)) {
                    addExpireTime = userVipExpireTime.getTime() + addExpireTime;
                } else {
                    addExpireTime = now.getTime() + addExpireTime;
                }
                Date newVipExpireTime = new Date(addExpireTime);
                user.setVipExpireTime(newVipExpireTime);
                user.setIsVip(UserVipEnum.VIP.getValue());
                // 没有生成则vip_number
                if (user.getVipNumber() == null) {
                    sequenceVipMapper.replaceSequence();
                    Long vipNumber = sequenceVipMapper.getNextVipNumber();
                    user.setVipNumber(vipNumber);
                }
                // 乐观锁
                boolean update = this.lambdaUpdate().eq(VipExchangeCode::getCode, code)
                        .gt(VipExchangeCode::getSurplusCount, 0)
                        .setSql("used_count = used_count + 1")
                        .setSql("surplus_count = surplus_count - 1")
                        .update();
                if (!update) {
                    throw new BusinessException(ErrorEnum.RESOURCE_SURPLUS_ZERO, "兑换码已兑换完");
                }

                UserVipExchange userVipExchange = new UserVipExchange();
                userVipExchange.setUserId(userId);
                userVipExchange.setCode(code);
                // 更新用户信息
                userSession.set(UserSession.convert(user));

                return userService.updateById(user) && userVipExchangeService.save(userVipExchange);
            }));
        }
        // 更新当前用户信息
        httpServletRequest.getSession().setAttribute(AuthConstant.LOGIN_USER, userSession.get());
        return res;
    }
}




